#include <Ogre.h>
#include <OIS/OIS.h>
using namespace Ogre;

#include "MarbleMax.h"

bool Marble_Max::buildState(const FrameEvent& evt)
{
	switch(currBuildMode)
	{
	case BM_BUILD:
		return bsBuild(evt);
		break;
	case BM_BULLDOZE:
		return bsBulldoze(evt);
		break;
	default:
		return false;
	}
}

bool Marble_Max::bsBuild(const Ogre::FrameEvent &evt)
{
	//mDebugString.clear();					// clear the debug string

	if (evt.timeSinceLastFrame == 0)		// If this is the first frame, pick a speed
	{
		mMoveScale = .1;
		mRotScale = 0.1;
	}
	else									// Otherwise scale movement units by time passed since last frame
	{
											// Move about 100 units per second,
		mMoveScale = (mMoveSpeed * evt.timeSinceLastFrame);
											// Take about 10 seconds for full rotation
		mRotScale = mRotSpeed * evt.timeSinceLastFrame;
	}
	mMouse->capture();						// capture the mouse's current state
	mKeyboard->capture();					// capture the keyboard's current state

	mTranslateVector = mMoveVector.normalisedCopy() * mMoveScale;		// set the translation vector to be 100 units long and in the right direction
	moveCamera();							// move the camera

	updateMouseObject();
	if(mLeftMUp)
	{
		placeObject();
		mLeftMUp = false;
	}

	mRotX = 0;
	mRotY = 0;
	//Sleep(500);
	return true;
}

Ogre::Vector2 Marble_Max::buildQuery()
{
	Ogre::Vector3 vec = Vector3::ZERO;
	mRaySceneQuery->setSortByDistance(true);
	RaySceneQueryResult &result = mRaySceneQuery->execute();
	RaySceneQueryResult::iterator itr;
	for(itr = result.begin();itr!= result.end();itr++)
	{
		/*if(itr->movable && itr->movable->getName().substr(0,8)=="MMObject")
		{
			mouseLoc = Vector2(itr->movable->getParentNode()->getPosition().x,itr->movable->getParentNode()->getPosition().z);
			break;
		}*/
		if(itr->worldFragment)
		{
			vec = itr->worldFragment->singleIntersection;
			mouseLoc.x = int(vec.x) - int(vec.x)%10 + 5;
			mouseLoc.y = int(vec.z) - int(vec.z)%10 + 5;
		}
	}
	return mouseLoc;
}

bool Marble_Max::placeObject()
{
	//query mouse for position for object - loc
	//query file for mesh - ent
	//query file for size - size
	//query file for killable - killable
	//query file for active - active
	Entity *ent;
	Vector3 vec = mouseNode->getPosition();
	bool killable = true;
	bool active = false;
	Ogre::Radian direction;

	Ogre::String tempName = "MMObject_" + StringConverter::toString(numObjects);
	tempNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(tempName + "_node",vec,mouseNode->getOrientation());
	ent = mSceneMgr->getEntity(mouseNode->getAttachedObject(0)->getName());
	tempEntity = mSceneMgr->createEntity(tempName + "_mesh",ent->getMesh()->getName());
	tempEntity->setMaterialName("SetCube");
	tempNode->attachObject(tempEntity);
	tempNode->scale(mouseNode->getScale());

	space[int(vec.x / 10)][int(vec.y / 10)][int(vec.z / 10)] = false;
	switch(mCurrTrack)
	{
	case NORMAL:
		break;
	case HALF:
		space[int(vec.x/10)][int(vec.y/10 + 1)][int(vec.z/10)] = false;
		direction = mouseNode->getOrientation().getYaw();
		if(Ogre::Math::Sin(direction) == 1)
		{
			space[int(vec.x/10)][int(vec.y/10)][int(vec.z/10 - 1)] = false;
			space[int(vec.x/10)][int(vec.y/10 + 1)][int(vec.z/10 - 1)] = false;
		}
		else if(Ogre::Math::Sin(direction) == -1)
		{
			space[int(vec.x/10)][int(vec.y/10)][int(vec.z/10 + 1)] = false;
			space[int(vec.x/10)][int(vec.y/10 + 1)][int(vec.z/10 + 1)] = false;
		}
		else if(Ogre::Math::Sin(direction) == 0)
		{
			if(Ogre::Math::Cos(direction) == 1)
			{
				space[int(vec.x/10 + 1)][int(vec.y/10)][int(vec.z/10)] = false;
				space[int(vec.x/10 + 1)][int(vec.y/10 + 1)][int(vec.z/10)] = false;
			}
			if(Ogre::Math::Cos(direction) == -1)
			{
				space[int(vec.x/10 - 1)][int(vec.y/10)][int(vec.z/10)] = false;
				space[int(vec.x/10 - 1)][int(vec.y/10 + 1)][int(vec.z/10)] = false;
			}
		}
		break;
	case DOUBLE:
		space[int(vec.x / 10)][int(vec.y / 10) + 1][int(vec.z / 10)] = false;
		break;
	case SINGLE:
		break;
	case SHARP:
		break;
	}

	Objects.push_back(Object(tempName,vec,tempNode,tempEntity,Vector3(1,1,1),killable,active));
	numObjects++;

	return true;
}

bool Marble_Max::checkForSpace()
{
	buildQuery();

	vector<Object> &result = Objects;
	vector<Object>::iterator itr;
	/*for(itr = result.begin(); itr != result.end(); itr++)
	{
		if(itr->getLocation() == Vector3(mouseLoc.x, objectHeight,mouseLoc.y))
			return false;
	}*/
	if(space[int(mouseLoc.x / 10)][objectHeight / 10][int(mouseLoc.y / 10)])
		return true;
	else
		return false;
}
int Marble_Max::getSpace()
{
	int height = objectHeight / 10;
	bool tspace = false;
	bool moved = false;
	vector<Object> &result = Objects;
	vector<Object>::iterator itr;
	while(!tspace)
	{
		/*for(itr = result.begin(); itr != result.end(); itr++)
		{
			if(itr->getLocation().x == mouseLoc.x && itr->getLocation().z == mouseLoc.y)
			{
				if(itr->getLocation().y == height)
				{
					height += 10;
					moved = true;
				}
			}
		}
		if(!moved)
			itr++;
		if(itr == result.end())
		{
			space = true;
		}
		moved = false;*/

		if(space[int(mouseLoc.x / 10)][height][int(mouseLoc.y / 10)])
			tspace = true;
		else
			height++;
	}
	return height * 10;
}
bool Marble_Max::updateMouseObject()
{
	switch(currBuildMode)
	{
	case BM_BUILD:
		if(checkForSpace())
		{
			mouseNode->setPosition(mouseLoc.x,objectHeight,mouseLoc.y);
		}
		else
		{
			mouseNode->setPosition(mouseLoc.x,getSpace(),mouseLoc.y);
		}
		break;
	case BM_BULLDOZE:
		if(bulldozeQuery() == "_negative")
			mouseNode->setPosition(mouseLoc.x,objectHeight,mouseLoc.y);
		break;
	}
	return true;
}


bool Marble_Max::bsBulldoze(const Ogre::FrameEvent &evt)
{
	
	//mDebugString.clear();					// clear the debug string

	if (evt.timeSinceLastFrame == 0)		// If this is the first frame, pick a speed
	{
		mMoveScale = .1;
		mRotScale = 0.1;
	}
	else									// Otherwise scale movement units by time passed since last frame
	{
											// Move about 100 units per second,
		mMoveScale = (mMoveSpeed * evt.timeSinceLastFrame);
											// Take about 10 seconds for full rotation
		mRotScale = mRotSpeed * evt.timeSinceLastFrame;
	}
	mMouse->capture();						// capture the mouse's current state
	mKeyboard->capture();					// capture the keyboard's current state

	mTranslateVector = mMoveVector.normalisedCopy() * mMoveScale;		// set the translation vector to be 100 units long and in the right direction
	moveCamera();							// move the camera

	updateMouseObject();
	if(mLeftMUp)
	{
		removeObject();
		mLeftMUp = false;
	}

	mRotX = 0;
	mRotY = 0;
	return true;
}

bool Marble_Max::removeObject()
{
	Ogre::String str = bulldozeQuery();
	if(str == "_negative")
		return false;
	vector<Object>::iterator itr;
	for(itr = Objects.begin(); itr != Objects.end(); itr++)
	{
		if((itr->getName() + "_mesh") == str)
		{
			if(itr->isDestructable())
			{
				space[int(itr->getLocation().x/10)][int(itr->getLocation().y/10)][int(itr->getLocation().z/10)] = true;
				mSceneMgr->destroySceneNode(itr->getNode());
				mSceneMgr->destroyEntity(itr->getEntity());
				Objects.erase(itr);
			}
			break;
		}
	}
	mouseNode = mSceneMgr->getSceneNode("BULLDOZENODE");
	return true;
}
Ogre::String Marble_Max::bulldozeQuery()
{
	Ogre::Vector3 vec = Vector3::ZERO;
	mRaySceneQuery->setSortByDistance(true);
	RaySceneQueryResult &result = mRaySceneQuery->execute();
	RaySceneQueryResult::iterator itr;
	Ogre::String str = "_negative";
	for(itr = result.begin();itr!= result.end();itr++)
	{
		if(itr->movable && itr->movable->getName().substr(0,8)=="MMObject")
		{
			if(mouseNode->getName() != itr->movable->getParentSceneNode()->getName())
			{
				mouseNode->showBoundingBox(false);
				if(mouseNode->getName().substr(0,8)!="MMObject")
					mouseNode->setVisible(false);
				else
					mSceneMgr->getEntity(mouseNode->getAttachedObject(0)->getName())->setMaterialName("SetCube");
				
				mouseNode = itr->movable->getParentSceneNode();
				mSceneMgr->getEntity(mouseNode->getAttachedObject(0)->getName())->setMaterialName("BulldozeCube");
				mouseNode->showBoundingBox(true);
			}

			str = itr->movable->getName();
			break;
		}
		else if(itr->worldFragment)
		{
			vec = itr->worldFragment->singleIntersection;
			mouseLoc.x = int(vec.x) - int(vec.x)%10 + 5;
			mouseLoc.y = int(vec.z) - int(vec.z)%10 + 5;

			if(mouseNode->getName() != "BULLDOZENODE")
			{
				if(mouseNode->getName().substr(0,8)=="MMObject")
				{
					mouseNode->showBoundingBox(false);
					mSceneMgr->getEntity(mouseNode->getAttachedObject(0)->getName())->setMaterialName("SetCube");
				}

				mouseNode = mSceneMgr->getSceneNode("BULLDOZENODE");
				mouseNode->showBoundingBox(true);
			}
		}
	}
	return str;
}

bool Marble_Max::increaseSlope()
{
	return true;
}
bool Marble_Max::decreaseSlope()
{
	return true;
}

/*
use vector to keep track of all boxes



@TODO
need to check mouse position to see if its currently in a piece's area according to its size, not according to its location

when buildquerying, need to get the mesh first, get the first space above it for objectHeight
then get world intersection, use for the x and y (z) of mouseObject




*/